#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <string>
#include <iostream>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <functional>

#include "Common.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"

using namespace LogModule;
using func_t = std::function<std::string(int sock,InetAddr& addr)>;

class TcpServer : public NoCopy
{
public:
    TcpServer(func_t func) : _listensockfd(-1), _isrunning(false),_func(func)
    {
    }
    void Init()
    {
        // 1、创建套接字
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd < 0)
        {
            std::cerr << "创建套接字失败" << std::endl;
            exit(SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket success: " << _listensockfd;

        // bind
        struct sockaddr_in sock;
        socklen_t len = sizeof(sock);
        sock.sin_family = AF_INET;
        sock.sin_port = htons(8080);
        sock.sin_addr.s_addr = INADDR_ANY;

        if (bind(_listensockfd, (struct sockaddr *)&sock, len) < 0)
        {
            std::cerr << "bind失败" << std::endl;
            exit(BIND_ERR);
        }

        // 开始监听
        if (listen(_listensockfd, 10) < 0)
        {
            std::cerr << "listen失败" << std::endl;
            exit(LISTEN_ERR);
        }
        LOG(LogLevel::INFO) << "listen success: " << _listensockfd;
    }

    void Service(int sockfd, InetAddr &addr)
    {
        while (true)
        {
            char buff[1024];
            read(sockfd, buff, sizeof(buff));
            LOG(LogLevel::INFO) << addr.StringAdd() << " say# " << buff;

            // lambda表达式当调用 _func的时候才会真正执行lambda表达式的内容
            std::string echo_string = _func(sockfd,addr);
            //std::string echo_string = addr.StringAdd();
            
            echo_string = echo_string + ":" + buff;
            write(sockfd,echo_string.c_str(),echo_string.size());
            echo_string.clear();
            memset(buff,0,sizeof(buff));
        }
    }

    void Run()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // 多进程
            // 接收连接,没有连接会阻塞
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listensockfd, CONV(peer), &len);
            if (sockfd < 0)
            {
                std::cerr << "accept失败" << std::endl;
                exit(ACCEPT_ERR);
            }

            // 网络转主机
            InetAddr addr(peer);
            LOG(LogLevel::INFO) << "accept success,InetAddr peer" << addr.StringAdd();

            int id = fork();
            if (id < 0)
            {
                LOG(LogLevel::FATAL) << "fork error" << _listensockfd;
                exit(FORK_ERR);
            }
            else if (id == 0)
            {
                // 子进程
                int sonid = fork();
                if (sonid > 0)
                    exit(1);
                // 孙子进程执行，(操作系统1做回收)
                // 如果不用孙子进程，而用的是子进程那么父进程就要进行阻塞等待回收，就算不阻塞等待，当进程很多的时候容易造成没有回收到导致僵尸进程。
                // 如果父进程阻塞等待，那么该进程的执行不就成了串行的了

                //对数据进行接收处理
                Service(sockfd, addr);
            }
            else
            {
                waitpid(id, nullptr, 0);
                // 父进程
            }

        }

        _isrunning = false;
    }

private:
    int _listensockfd;
    bool _isrunning;
    func_t _func;
};
